﻿// Genius
// Copyright (C) 2016 Dirk Friedenberger, www.frittenburger.de
//   
// This source file is subject to the Microsoft Public License (Ms-PL).
// http://www.opensource.org/licenses/ms-pl.html
// All other rights reserved.
using Genius.Brain.Shared.Locator;
using Genius.SlackBot.Shared;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.WebSockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Genius.Brain.Shared.BO;
using System.Web;
using Genius.SlackBot.Shared.Locator;
using Genius.Brain.Shared;

namespace Genius.SlackBot.Impl
{
    class SlackBot : ISlackBot
    {
        private IGenius _Genius;

        public string Api { get; set; }

        public string Path { get; set; }

        public string Token { get; set; }


        public void Start()
        {
          
            JObject json = Get("rtm.start", "");

            var self = json["self"];
            var name = self["name"].Value<string>();
            var id   = self["id"].Value<string>();
            _Genius = BrainLocator.GetGenius(id, name);

            _Genius.Modules.Add(BrainLocator.GetGeniusModule("VocabularyTrainer"));
            _Genius.Modules.Add(BrainLocator.GetGeniusModule("SmallTalk"));


            var channels = json["channels"];
            var channelConverter = SlackBotLocator.GetJsonToChannelConverter();

            foreach (var channel in channels)
            {
                var c = channelConverter.ConvertFrom(channel);
                _Genius.Channels.Add(c);
            }

            var ims = json["ims"];
            var imConverter = SlackBotLocator.GetJsonToIMConverter();
            foreach (var im in ims)
            {
                var i = imConverter.ConvertFrom(im);
                _Genius.IMs.Add(i);
            }

            var websocket_url = json["url"].Value<string>();
            Console.WriteLine(websocket_url);

            Connect(websocket_url).Wait();
            
        }

        private JObject Get(string method, string param)
        {
            String url = Api + method + "?token=" + Token + param + "&pretty=1";
            using (WebClient wc = new WebClient())
            {
                var str = wc.DownloadString(url);
                return JObject.Parse(str);
            }
        }

        public async Task Connect(string uri)
        {
            ClientWebSocket webSocket = null;

            try
            {
                webSocket = new ClientWebSocket();
                await webSocket.ConnectAsync(new Uri(uri), CancellationToken.None);

                
                while (webSocket.State == WebSocketState.Open)
                {
                    ArraySegment<Byte> recvBuffer = new ArraySegment<byte>(new Byte[8192]);

                    WebSocketReceiveResult result = null;

                    using (var ms = new MemoryStream())
                    {
                        do
                        {
                            result = await webSocket.ReceiveAsync(recvBuffer, CancellationToken.None);
                            ms.Write(recvBuffer.Array, recvBuffer.Offset, result.Count);
                        }
                        while (!result.EndOfMessage);

                        ms.Seek(0, SeekOrigin.Begin);

                        if (result.MessageType == WebSocketMessageType.Text)
                        {
                            using (var reader = new StreamReader(ms, Encoding.UTF8))
                            {
                                // do stuff
                                var str = reader.ReadToEnd();
                                JObject json = JObject.Parse(str);
                                Console.Write(json);
                                var type = json.GetValue("type").Value<string>();
                                switch (type)
                                {
                                    case "message":

                                        var converter = SlackBotLocator.GetJsonToMessageConverter();
                                        var reqMessage = converter.ConvertFrom(json);
                                        var resMessage = _Genius.RecvMessage(reqMessage);

                                        if(resMessage != null)
                                            postMessage(resMessage);
                                     
                                        //UTF8Encoding encoder = new UTF8Encoding();
                                        //byte[] sendBuffer = encoder.GetBytes(resp.ToString());
                                        //await webSocket.SendAsync(new ArraySegment<byte>(sendBuffer), WebSocketMessageType.Text, true, CancellationToken.None);


                                        break;

                                }
                             


                            }
                        }
                    }

                   // if (result.MessageType == WebSocketMessageType.Close)
                    //{
                      //  await webSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, string.Empty, CancellationToken.None);
                   // }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine("Exception: {0}", ex);
            }
            finally
            {
                if (webSocket != null)
                    webSocket.Dispose();
                Console.WriteLine();


                Console.WriteLine("WebSocket closed.");

            }
        }

        private void postMessage(IMessage message)
        {
            var text = HttpUtility.UrlEncode(message.Text);
            JObject resp = Get("chat.postMessage", "&channel="+ message.ChannelId+ "&text="+ text + "&as_user="+message.User);
            Console.WriteLine(resp);
        }
    }
}
